import { z } from 'zod'
import { OpenAPIRegistry, extendZodWithOpenApi } from '@asteasolutions/zod-to-openapi'
import path from 'path'
import fs from 'fs'
import fetch from 'node-fetch'
import { 
  validateFileType, 
  validateFileName,
  generateUniqueFileName, 
  ensureUploadDir,
  convertToPdf,
  extractFirstPages,
  extractFirstThreePages,
  cleanupTempFiles
} from '../models/file-processor.js'
import { processDocumentComplete, checkTrfResultCache, getTrfCacheStats, cleanTrfCache, clearAllTrfCache, buildTrfRequestPreview } from '../services/trf-api.js'
import {
  getAllCacheStats,
  cleanCacheByType,
  clearAllCache,
  getSupportedCacheTypes,
  getCacheStatsByType
} from '../services/cache-manager.js'
import {
  getOrderId,
  getOrderDetail,
  getSampleDataByOrderId,
  getEnquiryId,
  getEnquiryDetail,
  getSampleDataByEnquiryId,
  getUserLabBuInfo
} from '../models/gpo-api.js'
import { sendFileProcessingStats } from '../services/powerbi-stats.js'

extendZodWithOpenApi(z)

export const registryFile = new OpenAPIRegistry()

// 处理记录持久化相关
const getProcessedRegistryPath = () => path.join(process.cwd(), 'server', 'config', 'processed-files.json')

let __processingCurrent = 0
const __processingWaiters = []
const __PROCESSING_MAX = 1

async function acquireProcessingLock() {
  if (__processingCurrent < __PROCESSING_MAX) {
    __processingCurrent++
    return
  }
  await new Promise((resolve) => __processingWaiters.push(resolve))
  __processingCurrent++
}

function releaseProcessingLock() {
  __processingCurrent = Math.max(0, __processingCurrent - 1)
  const next = __processingWaiters.shift()
  if (next) next()
}

function readProcessedRegistry() {
  try {
    const registryPath = getProcessedRegistryPath()
    if (!fs.existsSync(registryPath)) {
      return []
    }
    const content = fs.readFileSync(registryPath, 'utf-8')
    const data = JSON.parse(content || '[]')
    return Array.isArray(data) ? data : []
  } catch (e) {
    console.warn('读取处理记录失败，使用空列表:', e?.message || e)
    return []
  }
}

function writeProcessedRegistry(list) {
  try {
    const registryPath = getProcessedRegistryPath()
    const dir = path.dirname(registryPath)
    if (!fs.existsSync(dir)) {
      fs.mkdirSync(dir, { recursive: true })
    }
    fs.writeFileSync(registryPath, JSON.stringify(list, null, 2), 'utf-8')
  } catch (e) {
    console.error('写入处理记录失败:', e?.message || e)
  }
}

function upsertProcessedRecord(record, { overwrite = false } = {}) {
  const list = readProcessedRegistry()
  const key = record.fileKey
  const idx = list.findIndex(r => r.fileKey === key)
  if (idx !== -1) {
    if (overwrite) {
      const currentCount = typeof list[idx].processCount === 'number' ? list[idx].processCount : 1
      list[idx] = { 
        ...list[idx], 
        ...record, 
        processCount: currentCount + 1,
        updatedAt: new Date().toISOString() 
      }
    } else {
      // 不覆盖时，保留历史，但也可以追加一条新记录
      list.push({ ...record, processCount: 1, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString() })
    }
  } else {
    list.push({ ...record, processCount: 1, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString() })
  }
  writeProcessedRegistry(list)
}

function findProcessedRecordsByKey(fileKey) {
  const list = readProcessedRegistry()
  return list.filter(r => r.fileKey === fileKey)
}

// 按fileKey或关键词搜索处理记录
export const searchProcessedRecordsController = async (ctx) => {
  try {
    const fileKey = (ctx.query?.fileKey || ctx.request.body?.fileKey || '').trim()
    const q = (ctx.query?.q || '').trim()

    const list = readProcessedRegistry()
    let records = []

    if (fileKey) {
      records = list.filter(r => r.fileKey === fileKey)
    } else if (q) {
      const lq = q.toLowerCase()
      records = list.filter(r =>
        String(r.fileKey || '').toLowerCase().includes(lq) ||
        String(r.originalName || '').toLowerCase().includes(lq) ||
        String(r.processedFileName || '').toLowerCase().includes(lq)
      )
    } else {
      ctx.status = 400
      ctx.body = { success: false, message: '缺少搜索参数：fileKey或q' }
      return
    }

    // 统计信息
    const totalProcessCount = records.reduce((sum, r) => sum + (typeof r.processCount === 'number' ? r.processCount : 1), 0)
    const recordCount = records.length
    const lastUpdatedTs = records.reduce((max, r) => {
      const t = new Date(r.updatedAt || r.createdAt || 0).getTime()
      return Math.max(max, t)
    }, 0)

    // 按更新时间降序
    records.sort((a, b) => new Date(b.updatedAt || b.createdAt) - new Date(a.updatedAt || a.createdAt))

    ctx.body = {
      success: true,
      message: '处理记录搜索完成',
      data: {
        records,
        stats: {
          recordCount,
          totalProcessCount,
          lastUpdated: lastUpdatedTs ? new Date(lastUpdatedTs).toISOString() : null
        }
      }
    }
  } catch (error) {
    console.error('搜索处理记录错误:', error)
    ctx.status = 500
    ctx.body = { success: false, message: '搜索处理记录失败', error: error.message }
  }
}

// 删除指定处理记录（按 fileId）
export const deleteProcessedRecordController = async (ctx) => {
  try {
    const fileId = (ctx.params?.fileId || ctx.request.body?.fileId || '').trim()
    const alsoDeleteFile = String(ctx.query?.deleteFile || '').toLowerCase() === 'true'

    if (!fileId) {
      ctx.status = 400
      ctx.body = { success: false, message: '缺少参数：fileId' }
      return
    }

    const list = readProcessedRegistry()
    const idx = list.findIndex(r => String(r.fileId) === String(fileId))

    if (idx === -1) {
      ctx.status = 404
      ctx.body = { success: false, message: `未找到处理记录：fileId=${fileId}` }
      return
    }

    const [deleted] = list.splice(idx, 1)
    writeProcessedRegistry(list)

    // 可选：同时删除已处理文件
    if (alsoDeleteFile && deleted?.processedFilePath) {
      try {
        if (fs.existsSync(deleted.processedFilePath)) {
          fs.unlinkSync(deleted.processedFilePath)
        }
      } catch (e) {
        console.warn('删除处理文件失败:', e?.message || e)
      }
    }

    ctx.body = {
      success: true,
      message: '处理记录已删除',
      data: {
        deletedRecord: deleted,
        remainingCount: list.length
      }
    }
  } catch (error) {
    console.error('删除处理记录错误:', error)
    ctx.status = 500
    ctx.body = { success: false, message: '删除处理记录失败', error: error.message }
  }
}

// 文件上传schema
const fileUploadSchema = z.object({
  files: z.any().openapi({ description: 'The files to upload' })
}).openapi({ description: 'File upload request' })

const fileUploadResponseSchema = z.object({
  success: z.boolean().openapi({ description: 'Upload success status', example: true }),
  message: z.string().openapi({ description: 'Response message', example: 'File uploaded successfully' }),
  data: z.object({
    fileId: z.string().openapi({ description: 'Generated file ID' }),
    originalName: z.string().openapi({ description: 'Original file name' }),
    processedFileName: z.string().openapi({ description: 'Processed file name' }),
    downloadUrl: z.string().openapi({ description: 'Download URL' }),
    dffInfo: z.object({
      type: z.enum(['order', 'enquiry']).openapi({ description: 'Type of GPO record' }),
      id: z.string().openapi({ description: 'GPO record ID' }),
      detail: z.object({}).openapi({ description: 'GPO record details' }),
      sampleData: z.object({}).optional().openapi({ description: 'Sample data if available' })
    }).optional().openapi({ description: 'DFF information retrieved from GPO' })
  }).optional().openapi({ description: 'File information' }),
  error: z.string().optional().openapi({ description: 'Error message if any' })
}).openapi({ description: 'File upload response' })

// 注册文件上传路径
registryFile.registerPath({
  method: 'post',
  path: '/api/file/upload',
  summary: '上传文件并处理为PDF指定页数',
  description: '上传一个或多个文件，验证后转换为PDF并提取指定页数供下载',
  request: {
    body: {
      content: {
        'multipart/form-data': {
          schema: fileUploadSchema
        }
      }
    }
  },
  responses: {
    200: {
      description: '文件处理成功',
      content: {
        'application/json': {
          schema: fileUploadResponseSchema
        }
      }
    },
    400: {
      description: '文件验证失败或处理错误',
      content: {
        'application/json': {
          schema: fileUploadResponseSchema
        }
      }
    }
  }
})

// TRF结果解析函数
function parseTrfResult(trfResult) {
  try {
    const extractedData = {}
    
    // 检查TRF结果的数据结构
    if (!trfResult) {
      console.warn('TRF结果为空')
      return {}
    }
    
    if (!trfResult.data) {
      console.warn('TRF结果中没有data字段')
      return {}
    }
    
    if (!trfResult.data.files || !Array.isArray(trfResult.data.files)) {
      console.warn('TRF结果中没有files数组')
      return {}
    }
    
    if (trfResult.data.files.length === 0) {
      console.warn('TRF结果中files数组为空')
      return {}
    }
    
    const fileResult = trfResult.data.files[0]
    if (!fileResult.result) {
      console.warn('TRF文件结果中没有result字段')
      return {}
    }
    
    const result = fileResult.result
    let validFieldCount = 0
    
    // 将TRF结果中的字段映射到GPO字段
    for (const [fieldCode, value] of Object.entries(result)) {
      const cleanFieldCode = String(fieldCode).trim()
      let stringValue = ''
      if (value !== null && value !== undefined) {
        stringValue = String(value).trim()
      }
      if (stringValue === 'null' || stringValue === 'undefined') {
        stringValue = ''
      }
      extractedData[cleanFieldCode] = stringValue
      if (stringValue !== '') validFieldCount++
    }
    
    console.log(`解析的TRF数据: 共${validFieldCount}个有效字段`, extractedData)
    return extractedData
    
  } catch (error) {
    console.error('解析TRF结果时出错:', error)
    throw new Error(`TRF结果解析失败: ${error.message}`)
  }
}

// GPO字段更新函数 - 简化版本
async function updateGpoFields(orderNo, extractedData, objectType, sgsToken) {
  try {
    console.log(`开始更新GPO字段: ${orderNo}, 类型: ${objectType}, 字段数量: ${Object.keys(extractedData).length}`)
    
    if (!orderNo) {
      throw new Error('订单号不能为空')
    }
    
    if (!extractedData || Object.keys(extractedData).length === 0) {
      throw new Error('没有有效的字段数据需要更新')
    }
    
    if (!sgsToken) {
      throw new Error('缺少SGS Token，无法调用GPO API')
    }
    
    // 根据环境选择API地址
    const isProduction = process.env.NODE_ENV === 'production'
    const gpoUpdateUrl = isProduction 
      ? 'https://cnapp.sgs.net/gpo-micro-api/ai/tool/update'
      : 'https://cnapp-uat.sgs.net/gpo-micro-api/ai/tool/update';
    // 构建符合GPO API文档的请求结构（按 test.json 的完整结构）
    const requestData = {
      objectNo: orderNo,
      objectType: objectType.toLowerCase(),
      productLineCode: 'HL'
    }

    // 简化取值函数
    const getVal = (key) => {
      if (!Object.prototype.hasOwnProperty.call(extractedData, key)) return undefined
      const v = extractedData[key]
      if (v === null || v === undefined) return ''
      return String(v)
    }

    // Applicant 信息
    const applicant = {}
    const applicantKeys = {
      contactName: 'ApplicantContactPersonName',
      email: 'ApplicantContactPersonEmail',
      fax: 'ApplicantContactPersonFax',
      telephone: 'ApplicantContactPersonTelephone',
      mobile: 'ApplicantContactPersonMobile'
    }
    for (const [k, src] of Object.entries(applicantKeys)) {
      const val = getVal(src)
      if (val !== undefined) applicant[k] = val
    }
    if (Object.keys(applicant).length > 0) {
      requestData.applicant = applicant
    }

    // Payer 信息
    const payer = {}
    const payerKeys = {
      contactName: 'PayerContactPersonName',
      email: 'PayerContactPersonEmail',
      fax: 'PayerContactPersonFax',
      telephone: 'PayerContactPersonTelephone',
      mobile: 'PayerContactPersonMobile'
    }
    for (const [k, src] of Object.entries(payerKeys)) {
      const val = getVal(src)
      if (val !== undefined) payer[k] = val
    }
    if (Object.keys(payer).length > 0) {
      requestData.payer = payer
    }

    // Buyer 信息（若存在联系人字段则填充）
    const buyer = {}
    const buyerKeys = {
      contactName: 'BuyerContactPersonName',
      email: 'BuyerContactPersonEmail',
      fax: 'BuyerContactPersonFax',
      telephone: 'BuyerContactPersonTelephone',
      mobile: 'BuyerContactPersonMobile'
    }
    for (const [k, src] of Object.entries(buyerKeys)) {
      const val = getVal(src)
      if (val !== undefined) buyer[k] = val
    }
    if (Object.keys(buyer).length > 0) {
      requestData.buyer = buyer
    }

    // Agent 信息（若存在相关字段则填充）
    const agent = {}
    const agentKeys = {
      customerNameCn: 'AgentName(In Chinese)',
      customerNameEn: 'AgentName(In English)',
      addressCn: 'AgentAddress(In Chinese)',
      addressEn: 'AgentAddress(In English)',
      contactName: 'AgentContactPersonName',
      email: 'AgentContactPersonEmail',
      fax: 'AgentContactPersonFax',
      telephone: 'AgentContactPersonTelephone',
      mobile: 'AgentContactPersonMobile'
    }
    for (const [k, src] of Object.entries(agentKeys)) {
      const val = getVal(src)
      if (val !== undefined) agent[k] = val
    }
    if (Object.keys(agent).length > 0) {
      requestData.agent = agent
    }

    // Supplier 信息（若存在相关字段则填充）
    const supplier = {}
    const supplierKeys = {
      customerNameCn: 'SupplierName(In Chinese)',
      customerNameEn: 'SupplierName(In English)',
      addressCn: 'SupplierAddress(In Chinese)',
      addressEn: 'SupplierAddress(In English)',
      contactName: 'SupplierContactPersonName',
      email: 'SupplierContactPersonEmail',
      fax: 'SupplierContactPersonFax',
      telephone: 'SupplierContactPersonTelephone',
      mobile: 'SupplierContactPersonMobile'
    }
    for (const [k, src] of Object.entries(supplierKeys)) {
      const val = getVal(src)
      if (val !== undefined) supplier[k] = val
    }
    if (Object.keys(supplier).length > 0) {
      requestData.supplier = supplier
    }

    // Manufacturer 信息
    const manufacturer = {}
    const manufacturerKeys = {
      customerNameCn: 'ManufacturerName(In Chinese)',
      customerNameEn: 'ManufacturerName(In English)',
      addressCn: 'ManufacturerAddress(In Chinese)',
      addressEn: 'ManufacturerAddress(In English)',
      contactName: 'ManufacturerContactPersonName',
      email: 'ManufacturerContactPersonEmail',
      fax: 'ManufacturerContactPersonFax',
      telephone: 'ManufacturerContactPersonTelephone',
      mobile: 'ManufacturerContactPersonMobile'
    }
    for (const [k, src] of Object.entries(manufacturerKeys)) {
      const val = getVal(src)
      if (val !== undefined) manufacturer[k] = val
    }
    // 兼容历史：若无Manufacturer英文名但有Applicant英文名，作为兜底更新
    if (!manufacturer.customerNameEn && getVal('ApplicantName(In English)')) {
      manufacturer.customerNameEn = getVal('ApplicantName(In English)')
    }
    if (Object.keys(manufacturer).length > 0) {
      requestData.manufacturer = manufacturer
    }

    // ReportInfo（结合报告抬头规则）
    const reportInfo = {}
    let reportHint = ''
    const gv = (k) => {
      const v = getVal(k)
      return v === undefined ? undefined : String(v)
    }
    const reportLanguage = gv('Report Language')
    const reportHeaderEnRaw = gv('Report Header(EN)')
    const reportAddressEnRaw = gv('Report Address(EN)')
    const headerDiffName = gv('report header is different from applicant Company Name')
    const headerDiffAddr = gv('report header is different from applicant Address')
    const splitHeaderName = gv('Name of the Customer报告抬头')
    const splitHeaderAddr = gv('Address of the Customer报告抬头')
    const headerMode = gv('Name and Address of the Customer报告抬头')
    const applicantName = gv('ApplicantName(In English)')
    const applicantAddr = gv('ApplicantAddress(EN)')
    const payerName = gv('PayerName(In English)')
    const payerAddr = gv('PayerAddress(EN)')

    if ((headerDiffName && headerDiffName.trim()) || (headerDiffAddr && headerDiffAddr.trim())) {
      reportInfo.sameAsApplicant = 0
      reportInfo.reportHeaderEn = (headerDiffName || '').trim()
      reportInfo.reportAddressEn = (headerDiffAddr || '').trim()
    } else if ((splitHeaderName && splitHeaderName.trim()) || (splitHeaderAddr && splitHeaderAddr.trim())) {
      reportInfo.sameAsApplicant = 0
      reportInfo.reportHeaderEn = (splitHeaderName || '').trim()
      reportInfo.reportAddressEn = (splitHeaderAddr || '').trim()
      if (!splitHeaderName?.trim() || !splitHeaderAddr?.trim()) {
        reportHint = '没有提供Report Header信息'
      }
    } else if ((headerMode || '').toLowerCase() === 'payer') {
      reportInfo.sameAsApplicant = 0
      const hdr = (payerName && payerName.trim()) ? payerName.trim() : 'Payer'
      const addr = (payerAddr && payerAddr.trim()) ? payerAddr.trim() : 'Payer'
      if (hdr === 'Payer' || addr === 'Payer') {
        reportHint = '没有提供Report Header信息'
      }
      reportInfo.reportHeaderEn = hdr
      reportInfo.reportAddressEn = addr
    } else {
      // 默认Applicant或未提供 headerMode
      if ((applicantName && applicantName.trim()) || (applicantAddr && applicantAddr.trim())) {
        reportInfo.sameAsApplicant = 0
        reportInfo.reportHeaderEn = (applicantName || '').trim()
        reportInfo.reportAddressEn = (applicantAddr || '').trim()
      } else {
        reportInfo.sameAsApplicant = 1
        reportHint = '没有提供Report Header信息'
      }
    }

    if (reportLanguage && reportLanguage.trim()) reportInfo.reportLanguage = reportLanguage.trim()
    if (reportHeaderEnRaw && reportHeaderEnRaw.trim()) reportInfo.reportHeaderEn = reportHeaderEnRaw.trim()
    if (reportAddressEnRaw && reportAddressEnRaw.trim()) reportInfo.reportAddressEn = reportAddressEnRaw.trim()
    if (Object.keys(reportInfo).length > 0) {
      requestData.reportInfo = reportInfo
    }

    // ServiceRequirement
    const serviceRequirement = {}
    const invoiceDeliverWay = getVal('Invoice Deliver Way')
    if (invoiceDeliverWay !== undefined) serviceRequirement.invoiceDeliverWay = invoiceDeliverWay
    const softCopyDeliverToRaw = getVal('SoftCopy Deliver To')
    const parseDeliverTo = (raw) => {
      if (!raw) return []
      const tokens = raw.split(/[,;\s]+/).map(t => t.trim().toLowerCase()).filter(Boolean)
      const normalized = new Set()
      for (const t of tokens) {
        if (['applicant'].includes(t)) normalized.add('applicant')
        if (['payer'].includes(t)) normalized.add('payer')
        if (['buyer'].includes(t)) normalized.add('buyer')
        if (['agent'].includes(t)) normalized.add('agent')
        if (['supplier'].includes(t)) normalized.add('supplier')
        if (['manufacturer'].includes(t)) normalized.add('manufacturer')
      }
      return Array.from(normalized)
    }
    const contactInfos = []
    if (softCopyDeliverToRaw !== undefined) {
      contactInfos.push({
        contactsType: 'softCopyDeliverTo',
        deliverOthers: '',
        deliverTo: parseDeliverTo(softCopyDeliverToRaw)
      })
    }
    if (contactInfos.length > 0) {
      serviceRequirement.contactInfos = contactInfos
    }
    if (Object.keys(serviceRequirement).length > 0) {
      requestData.serviceRequirement = serviceRequirement
    }

    // dffList：根据CSV中type为DFF的FieldCode动态增减，并结合TRF数据填充
    let dffFieldCodes = []
    try {
      const cached = await checkTrfResultCache(orderNo)
      dffFieldCodes = cached?.csv_meta?.dff_fieldcodes || []
      // console.log(`[DEBUG] CSV缓存DFF字段数: ${dffFieldCodes.length}`)
      // console.log('[DEBUG] CSV记录的DFF字段:', dffFieldCodes)
    } catch (e) {
      console.warn('获取CSV DFF字段代码失败，使用默认映射:', e?.message || e)
    }

    // 映射：CSV FieldCode -> dffList目标路径与键（结合TRF字段源）；
    // 对未列举的字段启用驼峰命名兜底映射到 product
    const toCamelCase = (str) => {
      if (!str || typeof str !== 'string') return str
      // 将首字母小写，保留中间大小写与数字；处理下划线/空格/连字符为边界
      const cleaned = str.replace(/[^A-Za-z0-9_\-\s]/g, '')
      const parts = cleaned.split(/[\s_\-]+/).filter(Boolean)
      if (parts.length === 0) return ''
      const first = parts[0].charAt(0).toLowerCase() + parts[0].slice(1)
      const rest = parts.slice(1).map(p => p.charAt(0).toUpperCase() + p.slice(1))
      return [first, ...rest].join('')
    }
    const dictionaryMap = {
      ProductDescription: { section: 'product', key: 'productDescription' },
      ItemNo: { section: 'product', key: 'itemNo' },
      StyleNo: { section: 'product', key: 'styleNo' },
      AgeGroup: { section: 'product', key: 'ageGroup' },
      CountryOfOrigin: { section: 'product', key: 'countryOfOrigin' },
      CountryOfDestination: { section: 'product', key: 'countryOfDestination' },
      BuyerAliase: { section: 'product', key: 'buyerAliase' },
      ProductColor: { section: 'product', key: 'productColor' },
      PONo: { section: 'product', key: 'poNo' },
      LotNo: { section: 'product', key: 'lotNo' },
      ProductType: { section: 'product', key: 'productType' },
      VendorNo: { section: 'product', key: 'vendorNo' },
      SampleID: { section: 'sample', key: 'sampleID' },
      OtherSampleInformation: { section: 'sample', key: 'otherSampleInformation' },
      SampleProductDescription: { section: 'sample', key: 'productDescription' }
    }

    // 支持模式化键映射（如 RefCode1..4、SpecialCustomerAttributeX、SpecialProductAttributeX）
    const mapCodeToTarget = (code) => {
      if (dictionaryMap[code]) return dictionaryMap[code]
      let m
      if ((m = code.match(/^RefCode(\d+)$/))) {
        return { section: 'product', key: `refCode${m[1]}` }
      }
      if ((m = code.match(/^SpecialCustomerAttribute(\d+)$/))) {
        return { section: 'product', key: `specialCustomerAttribute${m[1]}` }
      }
      if ((m = code.match(/^SpecialProductAttribute(\d+)$/))) {
        return { section: 'product', key: `specialProductAttribute${m[1]}` }
      }
      return null
    }

    const product = {}
    const sample = {}
    const unmappedCodes = []
    const excludedEmptyCodes = []
    console.log('[DEBUG] TRF解析出fieldCode:', Object.keys(extractedData))

    // 优先按CSV控制的字段集进行映射；若未提供则尝试对所有TRF字段做映射
    const candidateCodes = (dffFieldCodes && dffFieldCodes.length > 0)
      ? dffFieldCodes
      : Object.keys(extractedData)

    for (const code of candidateCodes) {
      const target = mapCodeToTarget(code)
      const v = getVal(code)
      if (!target) {
        if (v === undefined) {
          excludedEmptyCodes.push(code)
          continue
        }
        const camelKey = toCamelCase(code)
        if (!camelKey) {
          unmappedCodes.push(code)
          continue
        }
        product[camelKey] = v
        console.log(`[DEBUG] DFF兜底映射: ${code} -> product.${camelKey} = ${v}`)
        continue
      }
      if (v === undefined) {
        excludedEmptyCodes.push(code)
        continue
      }
      if (target.section === 'product') {
        product[target.key] = v
      } else if (target.section === 'sample') {
        sample[target.key] = v
      }
    }

    if (unmappedCodes.length > 0) {
      console.log('[DEBUG] 未匹配到映射的DFF字段代码:', unmappedCodes)
    }
    if (excludedEmptyCodes.length > 0) {
      console.log('[DEBUG] 因空值被排除的DFF字段代码:', excludedEmptyCodes)
    }
    // sampleID为必填，若缺失则兜底
    if (!sample.sampleID) {
      sample.sampleID = 'A'
      sample.productDescription = product.productDescription
      sample.noOfSample = '1'
    }
    if (Object.keys(product).length > 0 || Object.keys(sample).length > 0) {
      const languageId = '1' // 默认英文
      requestData.dffList = [{
        languageId,
        product: Object.keys(product).length > 0 ? product : undefined,
        productSamples: [sample]
      }]
      console.log('[DEBUG] 生成的dffList:', JSON.stringify(requestData.dffList, null, 2))
    }
    
    console.log('GPO请求体:', JSON.stringify(requestData, null, 2))
    
    try {
      const response = await fetch(gpoUpdateUrl, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Sgstoken': sgsToken
        },
        body: JSON.stringify(requestData)
      })
      
      if (!response.ok) {
        const errorText = await response.text()
        console.error('GPO API响应错误:', response.status, errorText)
        // 抛出包含API详细错误信息的错误
        throw new Error(`GPO API Error: ${response.status} - ${errorText}`)
      }
      
      const result = await response.json()
      if (reportHint) {
        result.message = (result?.message ? String(result.message) + ' | ' : '') + reportHint
      }
      if (result?.success) {
        console.log('GPO字段更新成功:', result)
      } else {
        console.warn('GPO字段更新失败:', result)
      }
      return { requestData, result }
      
    } catch (apiError) {
      // 处理GPO API调用错误
      console.error('GPO API调用失败:', apiError)
      
      if (apiError.message.includes('无法找到订单') || apiError.message.includes('无法找到询价单')) {
        throw new Error(`${objectType === 'order' ? '订单' : '询价单'}不存在: ${orderNo}`)
      } else if (apiError.message.includes('HTTP错误: 401')) {
        throw new Error('认证失败，请重新登录')
      } else if (apiError.message.includes('HTTP错误: 403')) {
        throw new Error('权限不足，无法更新字段')
      } else if (apiError.message.includes('HTTP错误: 404')) {
        throw new Error('GPO API接口不存在')
      } else if (apiError.message.includes('HTTP错误: 500')) {
        throw new Error('GPO服务器内部错误')
      } else {
        throw new Error(`GPO API调用失败: ${apiError.message}`)
      }
    }
    
  } catch (error) {
    console.error('更新GPO字段时出错:', error)
    throw error
  }
}

// TRF API调用控制器
// 检查TRF结果缓存API控制器函数
export const checkTrfCacheController = async (ctx) => {
  try {
    const { orderNo } = ctx.request.body

    if (!orderNo) {
      ctx.status = 400
      ctx.body = {
        success: false,
        message: '缺少必要参数：orderNo'
      }
      return
    }

    console.log('检查TRF结果缓存:', orderNo)
    
    // 检查是否存在缓存结果
    const cachedResult = await checkTrfResultCache(orderNo)
    
    if (cachedResult) {
      ctx.body = {
        success: true,
        message: '找到TRF结果缓存',
        data: cachedResult,
        cached: true
      }
    } else {
      ctx.body = {
        success: true,
        message: '未找到TRF结果缓存',
        data: null,
        cached: false
      }
    }

  } catch (error) {
    console.error('检查TRF缓存错误:', error)
    ctx.status = 500
    ctx.body = {
      success: false,
      message: '检查TRF缓存失败',
      error: error.message
    }
  }
}

export const callTrfApiController = async (ctx) => {
  try {
    const { docFilePath, csvContent, orderNo } = ctx.request.body

    if (!docFilePath || !csvContent || !orderNo) {
      ctx.status = 400
      ctx.body = {
        success: false,
        message: '缺少必要参数：docFilePath, csvContent, orderNo'
      }
      return
    }

    // 检查文档文件是否存在
    const fullDocPath = path.resolve(docFilePath)
    if (!fs.existsSync(fullDocPath)) {
      ctx.status = 400
      ctx.body = {
        success: false,
        message: '文档文件不存在'
      }
      return
    }

    console.log('开始调用TRF API处理文档:', fullDocPath)
    
    // 调用TRF API处理文档
    const result = await processDocumentComplete(fullDocPath, csvContent, orderNo)
    let trfRequestData = null
    try {
      trfRequestData = buildTrfRequestPreview(csvContent, orderNo)
    } catch {}
    
    ctx.body = {
      success: true,
      message: 'TRF API调用成功',
      data: {
        ...result,
        trfRequestData
      }
    }

  } catch (error) {
    console.error('TRF API调用错误:', error)
    try {
      const ord = ctx.request.body?.orderNo || ''
      await sendErrorMail(ctx, ord, 'TRF识别', error?.message || String(error))
    } catch {}
    ctx.status = 500
    ctx.body = {
      success: false,
      message: 'TRF API调用失败',
      error: error.message
    }
  }
}

// DFF更新API控制器函数
export const updateDffController = async (ctx) => {
  try {
    const { objectNo, objectType, productLineCode, customerFields, serviceFields, dffFields, dffList } = ctx.request.body
    
    // 验证必需参数
    if (!objectNo || !objectType || !productLineCode) {
      ctx.status = 400
      ctx.body = {
        success: false,
        message: '缺少必需参数: objectNo, objectType, productLineCode'
      }
      return
    }
    
    // 验证objectType
    if (!['order', 'enquiry'].includes(objectType.toLowerCase())) {
      ctx.status = 400
      ctx.body = {
        success: false,
        message: 'objectType必须是order或enquiry'
      }
      return
    }
    
    // 根据环境选择API地址
    const isProduction = process.env.NODE_ENV === 'production'
    const gpoUpdateUrl = isProduction 
      ? 'https://cnapp.sgs.net/gpo-micro-api/ai/tool/update'
      : 'https://cnapp-uat.sgs.net/gpo-micro-api/ai/tool/update'
    
    console.log('调用DFF更新API:', { objectNo, objectType, productLineCode, gpoUpdateUrl })
    
    // 构建请求数据，按照order-api.md格式（该接口要求小写objectType）
    const requestData = {
      objectNo,
      objectType: objectType.toLowerCase() === 'enquiry' ? 'enquiry' : 'order',
      productLineCode
    }
    
    // 处理Customer字段 - 映射到applicant, payer, manufacturer
    // 根据API文档，applicant是必填字段，需要确保始终提供
    if (customerFields && (customerFields['ApplicantContactPersonName'] || customerFields['ApplicantContactPersonEmail'])) {
      // Applicant信息
      requestData.applicant = {
        contactName: customerFields['ApplicantContactPersonName'] || '',
        email: customerFields['ApplicantContactPersonEmail'] || ''
      }
    } else {
      // 提供默认的applicant信息以满足API必填要求
      requestData.applicant = {
        contactName: '',
        email: ''
      }
    }
    
    // Payer信息（可选）
    if (customerFields && (customerFields['PayerContactPersonName'] || customerFields['PayerContactPersonEmail'])) {
      requestData.payer = {
        contactName: customerFields['PayerContactPersonName'] || '',
        email: customerFields['PayerContactPersonEmail'] || ''
      }
    }
    
    // Manufacturer信息（可选）
    if (customerFields && customerFields['ManufacturerName(In English)']) {
      requestData.manufacturer = {
        customerNameEn: customerFields['ManufacturerName(In English)'] || ''
      }
    }
    
    // 处理Service字段 - 映射到serviceRequirement和reportInfo（按order-api.md）
    // 根据API文档校验逻辑：订单下ServiceRequirement为空时，不支持更新
    const sr = { contactInfos: [] }
    let hasSrField = false

    if (serviceFields) {
      // SoftCopy Deliver To
      if (serviceFields['SoftCopy Deliver To']) {
        sr.contactInfos.push({
          contactsType: 'softCopyDeliverTo',
          deliverOthers: serviceFields['SoftCopy Deliver To'],
          deliverTo: ['applicant']
        })
        hasSrField = true
      }

      // Invoice Deliver To（可选）
      if (serviceFields['Invoice Deliver To']) {
        sr.contactInfos.push({
          contactsType: 'invoiceDeliverTo',
          deliverOthers: serviceFields['Invoice Deliver To'],
          deliverTo: ['applicant']
        })
        hasSrField = true
      }

      // Return Sample To（可选）
      if (serviceFields['Return Sample To']) {
        sr.contactInfos.push({
          contactsType: 'returnSampleTo',
          deliverOthers: serviceFields['Return Sample To'],
          deliverTo: ['applicant']
        })
        hasSrField = true
      }

      // Invoice Deliver Way
      if (serviceFields['Invoice Deliver Way']) {
        sr.invoiceDeliverWay = serviceFields['Invoice Deliver Way']
        hasSrField = true
      }

      // Return Residue/Tested Sample（可选）
      if (serviceFields['Return Residue Sample Flag']) {
        sr.returnResidueSampleFlag = String(serviceFields['Return Residue Sample Flag'])
        hasSrField = true
      }
      if (serviceFields['Return Residue Sample Remark']) {
        sr.returnResidueSampleRemark = serviceFields['Return Residue Sample Remark']
        hasSrField = true
      }
      if (serviceFields['Return Tested Sample Flag']) {
        sr.returnTestedSampleFlag = String(serviceFields['Return Tested Sample Flag'])
        hasSrField = true
      }

      if (hasSrField) {
        requestData.serviceRequirement = sr
      }
    }
    
    // 确保serviceRequirement始终存在且包含必要的联系信息（API文档要求：订单下ServiceRequirement为空时，不支持更新）
    if (!requestData.serviceRequirement) {
      requestData.serviceRequirement = { 
        contactInfos: [
          {
            "contactsType": "softCopyDeliverTo",
            "deliverTo": ["applicant"]
          }
        ]
      }
    } else if (!requestData.serviceRequirement.contactInfos || requestData.serviceRequirement.contactInfos.length === 0) {
      // 如果contactInfos为空数组，提供默认联系信息
      requestData.serviceRequirement.contactInfos = [
        {
          "contactsType": "softCopyDeliverTo", 
          "deliverTo": ["applicant"]
        }
      ]
    }

    // ReportInfo：只有在同时提供Header与Address时才更新，避免后端校验失败
    // 添加安全检查，确保serviceFields存在
    const sameAsApplicantVal = serviceFields && serviceFields['Same As Applicant']
    const reportLanguageVal = serviceFields && serviceFields['Report Language']
    const reportHeaderEn = serviceFields && serviceFields['Report Header (English)']
    const reportHeaderCn = serviceFields && serviceFields['Report Header (Chinese)']
    const reportAddressEn = serviceFields && serviceFields['Report Address (English)']
    const reportAddressCn = serviceFields && serviceFields['Report Address (Chinese)']
    const hasHeader = !!(reportHeaderEn || reportHeaderCn)
    const hasAddress = !!(reportAddressEn || reportAddressCn)
    const needsReportInfoUpdate = [sameAsApplicantVal, reportLanguageVal, reportHeaderEn, reportHeaderCn, reportAddressEn, reportAddressCn]
      .some(v => v !== undefined && v !== '')

    if (needsReportInfoUpdate) {
      if (hasHeader && hasAddress) {
        requestData.reportInfo = {}
        if (sameAsApplicantVal !== undefined && sameAsApplicantVal !== '') {
          requestData.reportInfo.sameAsApplicant = ['1', 'true', 1, true].includes(sameAsApplicantVal) ? 1 : 0
        }
        if (reportLanguageVal !== undefined && reportLanguageVal !== '') {
          requestData.reportInfo.reportLanguage = String(reportLanguageVal)
        }
        requestData.reportInfo.reportHeaderEn = reportHeaderEn || ''
        requestData.reportInfo.reportHeaderCn = reportHeaderCn || ''
        requestData.reportInfo.reportAddressEn = reportAddressEn || ''
        requestData.reportInfo.reportAddressCn = reportAddressCn || ''
      } else {
        console.warn('跳过ReportInfo更新：缺少Header或Address，避免后端校验失败')
      }
    }
    
    // 处理DFF字段和原始dffList
    // 根据API文档校验逻辑：订单下不存在DFF信息时，不支持更新
    if (!dffList || !Array.isArray(dffList) || dffList.length === 0) {
      ctx.status = 400
      ctx.body = {
        success: false,
        message: 'DFF更新失败: dffList不能为空，根据API文档要求订单下必须存在DFF信息'
      }
      return
    }
    
    // 验证dffList结构（API文档要求：DFF下的SampleList中，SampleID和LanguageID不能为空）
    for (const dff of dffList) {
      if (!dff.languageId) {
        ctx.status = 400
        ctx.body = {
          success: false,
          message: 'dffList中每个项目都必须包含languageId'
        }
        return
      }
      
      if (dff.productSamples && Array.isArray(dff.productSamples)) {
        for (const sample of dff.productSamples) {
          if (!sample.sampleID) {
            ctx.status = 400
            ctx.body = {
              success: false,
              message: 'productSamples中每个样品都必须包含sampleID'
            }
            return
          }
        }
      }
    }
    
    // 处理dffList中的空字符串字段，根据API文档要求lotNo和refCode1不能为空字符串
    const processedDffList = dffList.map(dff => ({
      ...dff,
      product: {
        ...dff.product,
        // 为空字符串提供默认值
        lotNo: dff.product.lotNo && dff.product.lotNo.trim() ? dff.product.lotNo : 'N/A',
        refCode1: dff.product.refCode1 && dff.product.refCode1.trim() ? dff.product.refCode1 : 'N/A'
      }
    }))
    
    requestData.dffList = processedDffList

    // 样品ID一致性校验：若提供了样品ID，则确认其属于该订单/询价
    try {
      const sgsToken = ctx.state?.user?.sgsToken || ctx.headers.sgstoken || ctx.headers.Sgstoken || ''
      const submittedSampleIds = new Set()
      for (const dff of (dffList || [])) {
        for (const s of (dff.productSamples || [])) {
          if (s?.sampleID) submittedSampleIds.add(String(s.sampleID))
        }
      }
      if (submittedSampleIds.size > 0 && sgsToken) {
        const { getOrderId, getEnquiryId, getSampleDataByOrderId, getSampleDataByEnquiryId } = await import('../models/gpo-api.js')
        let sampleData = null
        if (requestData.objectType === 'order') {
          const orderId = await getOrderId(objectNo, sgsToken)
          if (orderId) sampleData = await getSampleDataByOrderId(orderId, sgsToken)
        } else {
          const enquiryId = await getEnquiryId(objectNo)
          if (enquiryId) sampleData = await getSampleDataByEnquiryId(enquiryId, sgsToken)
        }
        // 支持多种字段名形态：sampleID / sampleId / sampleNo
        const collectIds = (arr = []) => arr
          .map(ps => ps && (ps.sampleID ?? ps.sampleId ?? ps.sampleNo))
          .filter(id => id !== undefined && id !== null && String(id).trim() !== '')
          .map(id => String(id))

        const lists = Array.isArray(sampleData?.productSampleRspList)
          ? sampleData.productSampleRspList
          : []

        const allowed = new Set(
          lists.flatMap(item => collectIds(item?.productSamples || []))
        )
        console.log('样品ID一致性校验-允许列表:', [...allowed])
        const invalid = [...submittedSampleIds].filter(id => !allowed.has(id))
        if (invalid.length) {
          ctx.status = 400
          ctx.body = {
            success: false,
            message: `样品ID不属于该${requestData.objectType === 'enquiry' ? '询价单' : '订单'}: ${invalid.join(', ')}`,
            error: {
              type: 'INVALID_SAMPLE_IDS',
              submitted: [...submittedSampleIds],
              allowed: [...allowed]
            }
          }
          return
        }
      }
    } catch (sampleCheckError) {
      console.warn('样品ID一致性校验跳过:', sampleCheckError?.message || sampleCheckError)
    }
    
    // 检查认证信息
    const sgsToken = ctx.state?.user?.sgsToken
    if (!sgsToken) {
      console.error('DFF更新失败: 缺少SGS认证token')
      ctx.status = 401
      ctx.body = {
        success: false,
        message: 'DFF更新失败: 缺少SGS认证token，请重新登录'
      }
      return
    }
    
    // 打印请求体，便于定位上游"request invalid"
    console.log('即将调用GPO微服务，RequestData:', JSON.stringify(requestData))
    console.log('DFF更新API请求头:', {
      'Sgstoken': sgsToken ? '已提供' : '缺失',
      'Productlinecode': productLineCode
    })

    // 调用GPO微服务API（携带必要头）
    const response = await fetch(gpoUpdateUrl, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Sgstoken': sgsToken,
        'Productlinecode': productLineCode
      },
      body: JSON.stringify(requestData)
    })

    // 读取原始响应文本以便在JSON不合法或缺失详细错误时打印出来
    const rawText = await response.text()
    let result
    try {
      result = JSON.parse(rawText)
    } catch (e) {
      result = { success: false, message: '响应非JSON', raw: rawText }
    }
    console.log('DFF更新API响应状态:', response.status, response.statusText)
    console.log('DFF更新API响应原文:', rawText)
    
    if (response.ok && result.success) {
      ctx.body = {
        success: true,
        message: 'DFF数据更新成功',
        data: result.data
      }
    } else {
      // 如果上游HTTP为200但返回success=false，使用上游的status字段或默认500
      const computedStatus = response.ok
        ? (typeof result?.status === 'number' ? result.status : 500)
        : (response.status || 500)

      ctx.status = computedStatus
      const errorPayload = {
        success: false,
        message: result?.message || 'DFF数据更新失败',
        error: result,
        rawResponse: result?.raw ? result.raw : undefined
      }
      ctx.body = errorPayload
    }
    
  } catch (error) {
    console.error('DFF更新API调用失败:', error)
    ctx.status = 500
    ctx.body = {
      success: false,
      message: 'DFF更新API调用失败',
      error: error.message
    }
  }
}

// 文件上传和处理
export const uploadAndProcessFiles = async (ctx) => {
  const tempFiles = []
  const processedFiles = []
  const errors = []
  const overwriteFlagRaw = ctx.request.body?.overwrite
  const overwrite = String(overwriteFlagRaw).toLowerCase() === 'true'
  
  try {
    console.log('进入文件上传处理接口 /api/file/upload')
    console.log('请求体:', ctx.request.body)
    console.log('文件信息:', ctx.request.files)
    
    const hasFilesArray = Array.isArray(ctx.request.files) && ctx.request.files.length > 0
    const hasFilesField = ctx.request.files && Array.isArray(ctx.request.files.files) && ctx.request.files.files.length > 0
    if (!hasFilesArray && !hasFilesField) {
      ctx.status = 400
      ctx.body = { success: false, message: '没有上传文件' }
      return
    }

    await acquireProcessingLock()
    
    // 获取PDF页数参数，支持设为0；缺省时默认1页
    const parsedPageCount = parseInt(ctx.request.body?.pdfPageCount)
    const pdfPageCount = Number.isInteger(parsedPageCount) && parsedPageCount >= 0 ? parsedPageCount : 1
    console.log('PDF页数设置:', pdfPageCount)
    
    // 获取用户信息用于统计
    const userName = ctx.request.body?.userName || ctx.state?.user?.username || 'Unknown'
    
    // 获取用户的详细location信息
    let userLocation = 'Unknown'
    let labBuInfo = null
    
    // console.log('=== 开始获取用户location信息 ===')
    // console.log('初始userLocation:', userLocation)
    // console.log('用户状态信息:', ctx.state?.user)
    
    try {
      // 首先尝试从JWT token中获取locationName（已经在登录时获取并编码到token中）
      if (ctx.state?.user?.locationName) {
        userLocation = ctx.state.user.locationName
        // console.log('✓ 从JWT token中获取到locationName:', userLocation)
      } else {
        console.log('JWT token中没有locationName，尝试通过API获取')
        // 如果token中没有，再尝试通过API获取
        const sgsToken = ctx.state?.user?.sgsToken
        // console.log('用户状态信息:', { 
        //   hasUser: !!ctx.state?.user, 
        //   hasSgsToken: !!sgsToken,
        //   sgsToken: sgsToken ? '已提供' : '未提供'
        // })
        
        if (sgsToken) {
          console.log('正在调用getUserLabBuInfo API...')
          labBuInfo = await getUserLabBuInfo(sgsToken)
          // console.log('getUserLabBuInfo API完整响应:', labBuInfo)
          
          if (labBuInfo && labBuInfo.locationName) {
            userLocation = labBuInfo.locationName
            // console.log('✓ 成功从API获取locationName:', labBuInfo.locationName)
          } else {
            console.warn('getUserLabBuInfo响应中没有locationName字段')
            const fallbackLocation = ctx.request.body?.userLocation || ctx.state?.user?.location || 'Unknown'
            userLocation = fallbackLocation
            // console.log('使用fallback location:', fallbackLocation)
          }
        } else {
          console.warn('未找到sgsToken，无法调用getUserLabBuInfo')
          const fallbackLocation = ctx.request.body?.userLocation || ctx.state?.user?.location || 'Unknown'
          userLocation = fallbackLocation
          // console.log('使用fallback location:', fallbackLocation)
        }
      }
      
      // console.log('✓ location获取成功，最终userLocation:', userLocation)
      
    } catch (error) {
      console.error('❌ 获取用户location信息失败:', error)
      console.error('错误堆栈:', error.stack)
      const fallbackLocation = ctx.request.body?.userLocation || ctx.state?.user?.location || 'Unknown'
      userLocation = fallbackLocation
      console.log('使用异常处理fallback location:', fallbackLocation)
    }
    
    // console.log('=== location信息获取完成 ===')
    // console.log('最终结果 - userLocation:', userLocation)
    // console.log('最终结果 - labBuInfo存在:', !!labBuInfo)
    
    // console.log('用户信息:', { userName, userLocation })
    
    const files = hasFilesArray
      ? ctx.request.files
      : ctx.request.files.files
    
    console.log('处理文件数量:', files.length)
    
    // 确保上传目录存在
    const uploadDir = path.join(process.cwd(), 'uploads')
    const processedDir = path.join(process.cwd(), 'processed')
    ensureUploadDir(uploadDir)
    ensureUploadDir(processedDir)
    
    for (const file of files) {
      try {
        // 文件名校验
        const fileNameValidation = validateFileName(file.originalname)
        if (!fileNameValidation.isValid) {
          throw new Error(`文件名格式不正确: ${fileNameValidation.fileName}。支持的格式：Order格式/Enquiry格式`)
        }
        
        // 验证文件类型
        if (!validateFileType(file.mimetype)) {
          throw new Error(`不支持的文件类型: ${file.mimetype}`)
        }
        
        // 生成唯一文件名（仅用于临时存储，避免冲突）
        const uniqueFileName = generateUniqueFileName(file.originalname)
        const filePath = path.join(uploadDir, uniqueFileName)
        
        // 保存上传的文件
        let fileBuffer
        if (file.path) {
          // multer使用path属性而不是filepath
          fileBuffer = fs.readFileSync(file.path)
          // 将multer创建的临时文件也添加到清理列表
          tempFiles.push(file.path)
        } else if (file.filepath) {
          // 如果有filepath，从临时文件读取
          fileBuffer = fs.readFileSync(file.filepath)
          // 将multer创建的临时文件也添加到清理列表
          tempFiles.push(file.filepath)
        } else if (file.buffer) {
          // 如果有buffer，直接使用
          fileBuffer = file.buffer
        } else {
          console.error('文件对象缺少必要属性:', file)
          throw new Error('无法获取文件内容')
        }
        fs.writeFileSync(filePath, fileBuffer)
        tempFiles.push(filePath)
        
        // 转换为PDF（如果不是PDF文件）
        let pdfPath = filePath
        if (file.mimetype !== 'application/pdf') {
          try {
            pdfPath = await convertToPdf(filePath, file.mimetype)
            if (pdfPath !== filePath) {
              tempFiles.push(pdfPath)
            }
          } catch (error) {
            // 如果转换失败，跳过此文件
            console.error(`文件转换失败: ${file.originalname}`, error)
            continue
          }
        }
        
        // 提取指定页数；当设置为0时不进行删页处理
        let processedPdfPath = pdfPath
        let pageDeleteSkipped = false
        if (pdfPageCount > 0) {
          processedPdfPath = await extractFirstPages(pdfPath, pdfPageCount)
          pageDeleteSkipped = processedPdfPath === pdfPath
          // 将提取页数后生成的临时文件添加到清理列表
          if (processedPdfPath !== pdfPath) {
            tempFiles.push(processedPdfPath)
          }
        }
        
        // 使用原始文件名（不含扩展名）+ .pdf 作为最终文件名
        const originalBaseName = path.basename(file.originalname, path.extname(file.originalname))
        const finalFileName = `${originalBaseName}.pdf`
        const finalPath = path.join(processedDir, finalFileName)
        
        // 如果目标文件已存在，根据overwrite决定是否覆盖或添加时间戳
        let actualFinalPath = finalPath
        let actualFinalFileName = finalFileName
        if (fs.existsSync(finalPath)) {
          if (overwrite) {
            try {
              fs.unlinkSync(finalPath)
            } catch (e) {
              console.warn('覆盖旧文件时删除失败，继续替换:', e?.message || e)
            }
            actualFinalPath = finalPath
            actualFinalFileName = finalFileName
          } else {
            const timestamp = Date.now()
            actualFinalFileName = `${originalBaseName}_${timestamp}.pdf`
            actualFinalPath = path.join(processedDir, actualFinalFileName)
          }
        }
        
        try {
          fs.renameSync(processedPdfPath, actualFinalPath)
        } catch (renameErr) {
          console.warn('重命名目标文件失败，使用时间戳路径重试:', renameErr?.message || renameErr)
          const fallbackTs = Date.now()
          actualFinalFileName = `${originalBaseName}_${fallbackTs}.pdf`
          actualFinalPath = path.join(processedDir, actualFinalFileName)
          fs.renameSync(processedPdfPath, actualFinalPath)
        }
        
        // 获取DFF信息
        let dffInfo = null
        try {
          const fileNameValidation = validateFileName(file.originalname)
          if (fileNameValidation.isValid) {
            const { format, fileName } = fileNameValidation
            // 从JWT token中获取sgsToken，如果没有则从headers中获取（向后兼容）
            const sgsToken = ctx.state.user?.sgsToken || ctx.headers.sgstoken || ctx.headers.Sgstoken || ''
            
            if (format === 'order') {
              console.log(`获取Order DFF信息: ${fileName}`)
              const orderId = await getOrderId(fileName, sgsToken)
              if (orderId) {
                const orderDetail = await getOrderDetail(orderId, sgsToken)
                const sampleData = await getSampleDataByOrderId(orderId, sgsToken)
                dffInfo = {
                  type: 'order',
                  id: orderId,
                  detail: orderDetail,
                  sampleData: sampleData
                }
                console.log(`成功获取Order DFF信息:`, dffInfo)
              } else {
                console.warn(`未找到Order ID: ${fileName}`)
                dffInfo = {
                  type: 'order',
                  id: null,
                  detail: null,
                  sampleData: null,
                  error: {
                    type: 'ORDER_NOT_FOUND',
                    message: `订单号 "${fileName}" 查询失败`,
                    details: '请检查订单号是否正确，或联系管理员确认订单存在于系统中',
                    orderNo: fileName
                  }
                }
              }
            } else if (format === 'enquiry') {
              console.log(`获取Enquiry DFF信息: ${fileName}`)
              if (sgsToken) {
                const enquiryId = await getEnquiryId(fileName)
                if (enquiryId) {
                  const enquiryDetail = await getEnquiryDetail(enquiryId, sgsToken)
                  const sampleData = await getSampleDataByEnquiryId(enquiryId, sgsToken)
                  dffInfo = {
                    type: 'enquiry',
                    id: enquiryId,
                    detail: enquiryDetail,
                    sampleData: sampleData
                  }
                  console.log(`成功获取Enquiry DFF信息:`, dffInfo)
                } else {
                  console.warn(`未找到Enquiry ID: ${fileName}`)
                  dffInfo = {
                    type: 'enquiry',
                    id: null,
                    detail: null,
                    sampleData: null,
                    error: {
                      type: 'ENQUIRY_NOT_FOUND',
                      message: `询价单号 "${fileName}" 查询失败`,
                      details: '请检查询价单号是否正确，或联系管理员确认询价单存在于系统中',
                      enquiryNo: fileName
                    }
                  }
                }
              } else {
                console.warn('缺少sgsToken，无法获取Enquiry信息')
                dffInfo = {
                  type: 'enquiry',
                  id: null,
                  detail: null,
                  sampleData: null,
                  error: {
                    type: 'MISSING_TOKEN',
                    message: '缺少认证令牌，无法查询询价单信息',
                    details: '询价单查询需要有效的SGS Token，请重新登录或联系管理员',
                    enquiryNo: fileName
                  }
                }
              }
            }
          } else {
            console.warn(`文件名格式不符合要求: ${file.originalname}`)
            dffInfo = {
              type: null,
              id: null,
              detail: null,
              sampleData: null,
              error: {
                type: 'INVALID_FILENAME',
                message: '文件名格式不符合要求',
                details: '文件名应符合订单号或询价单号的命名规范，请检查文件名格式是否正确',
                fileName: file.originalname
              }
            }
          }
        } catch (error) {
          console.error('获取DFF信息时发生错误:', error)
          dffInfo = {
            type: null,
            id: null,
            detail: null,
            sampleData: null,
            error: {
              type: 'API_ERROR',
              message: 'DFF信息获取失败',
              details: `系统在获取DFF信息时发生错误: ${error.message}`,
              fileName: file.originalname,
              originalError: error.message
            }
          }
        }
        
        // 统计前置日志，便于定位
        // console.log('准备发送Power BI统计', {
        //   userName,
        //   userLocation,
        //   fileName: file.originalname
        // })

        // 发送Power BI统计数据，将完整结果包含在响应中
        let powerBiStats = null
        try {
          // console.log('准备发送Power BI统计数据:', { userName, userLocation, fileName: file.originalname })
          powerBiStats = await sendFileProcessingStats({
            userName: userName,
            userLocation: userLocation,
            fileName: file.originalname,
            sgsToken: ctx.state.user?.sgsToken, // 传递sgsToken以便在需要时重新获取location信息
            labBuInfo: labBuInfo // 传递已获取的labBuInfo，避免重复调用API
          })
          // console.log(`已发送Power BI统计数据: ${file.originalname}`, powerBiStats)
        } catch (statsError) {
          console.error(`发送Power BI统计数据失败: ${file.originalname}`, statsError)
          // 统计失败不影响文件处理流程
          powerBiStats = { 
            success: false, 
            message: 'Send stats failed', 
            error: statsError?.message,
            requestData: {
              userName: userName,
              userLocation: userLocation,
              fileName: file.originalname
            }
          }
        }

        const processedRecord = {
          fileId: actualFinalFileName.replace('.pdf', ''),
          fileKey: originalBaseName,
          originalName: file.originalname,
          processedFileName: actualFinalFileName,
          processedFilePath: path.resolve(processedDir, actualFinalFileName),
          downloadUrl: `/api/file/download/${actualFinalFileName}`,
          pageDeleteSkipped,
          dffInfo: dffInfo,
          powerBiStats
        }
        processedFiles.push(processedRecord)
        // 持久化记录
        upsertProcessedRecord(processedRecord, { overwrite })
        // console.log('文件处理成功，已加入processedFiles:', {
        //   fileId: actualFinalFileName.replace('.pdf', ''),
        //   originalName: file.originalname,
        //   processedFileName: actualFinalFileName,
        //   powerBiStats
        // })
        
      } catch (error) {
        console.error(`处理文件失败: ${file.originalname}`, error)
        try {
          const base = file.originalname.replace(/\.[^/.]+$/, '')
          await sendErrorMail(ctx, base, 'PDF处理', error?.message || String(error))
        } catch {}
        errors.push({
          file: file.originalname,
          message: error.message,
          stack: error.stack
        })
        // 继续处理其他文件
      }
    }
    
    // 清理临时文件
    cleanupTempFiles(tempFiles)
    
    ctx.status = 200
    ctx.body = {
      success: processedFiles.length > 0,
      message: processedFiles.length > 0 ? `成功处理 ${processedFiles.length} 个文件` : '没有文件被成功处理',
      data: processedFiles.length === 1 ? processedFiles[0] : processedFiles,
      errors
    }
    
    releaseProcessingLock()
    
  } catch (error) {
    console.error('文件处理错误:', error)
    
    // 确保清理临时文件
    cleanupTempFiles(tempFiles)
    
    ctx.status = 200
    ctx.body = {
      success: false,
      message: '服务器内部错误',
      error: error.message,
      errors
    }
    
    releaseProcessingLock()
  }
}

// 文件下载
export const downloadFile = async (ctx) => {
  try {
    const { filename } = ctx.params
    const filePath = path.join(process.cwd(), 'processed', filename)
    
    if (!fs.existsSync(filePath)) {
      ctx.status = 404
      ctx.body = {
        success: false,
        message: '文件不存在',
        error: '请求的文件未找到'
      }
      return
    }
    
    // 设置响应头
    ctx.set('Content-Type', 'application/pdf')
    ctx.set('Content-Disposition', `attachment; filename="${filename}"`)
    
    // 发送文件
    ctx.body = fs.createReadStream(filePath)
    
  } catch (error) {
    console.error('文件下载错误:', error)
    ctx.status = 500
    ctx.body = {
      success: false,
      message: '文件下载失败',
      error: error.message
    }
  }
}

// DFF模板查询控制器
export function processDffData(dffData) {
  if (!Array.isArray(dffData) || dffData.length === 0) {
    return []
  }
  
  const processedFields = []
  
  dffData.forEach(field => {
    const fieldInfo = {
      id: field.dFFFormID,
      label: field.label || field.displayName || '未知字段',
      dataType: field.dataType,
      required: field.required || false,
      allowEdit: field.allowEdit || false,
      values: []
    }
    
    // 处理字段的可选值
    if (field.dffFormAttrEvents && Array.isArray(field.dffFormAttrEvents)) {
      field.dffFormAttrEvents.forEach(event => {
        if (event.dffFormEventEffects && Array.isArray(event.dffFormEventEffects)) {
          event.dffFormEventEffects.forEach(effect => {
            if (effect.dffAttrValues && Array.isArray(effect.dffAttrValues)) {
              effect.dffAttrValues.forEach(value => {
                if (value.value && value.value.trim() !== '') {
                  fieldInfo.values.push({
                    value: value.value,
                    code: value.valueCode,
                    sequence: value.valueSequence,
                    isDefault: value.defaultSelectFlag === 1
                  })
                }
              })
            }
          })
        }
      })
    }
    
    processedFields.push(fieldInfo)
  })
  
  return processedFields
}

export const queryDffTemplateController = async (ctx) => {
  try {
    const { objectType, objectNo, productLineCode } = ctx.request.body
    
    // 验证必需参数
    if (!objectType || !objectNo || !productLineCode) {
      ctx.status = 400
      ctx.body = {
        success: false,
        message: '缺少必需参数: objectType, objectNo, productLineCode'
      }
      return
    }
    
    // 验证objectType
    if (!['Order', 'Enquiry'].includes(objectType)) {
      ctx.status = 400
      ctx.body = {
        success: false,
        message: 'objectType必须是Order或Enquiry'
      }
      return
    }
    
    // 根据环境选择API地址
    const isProduction = process.env.NODE_ENV === 'production'
    const gpoApiUrl = isProduction 
      ? 'https://cnapp.sgs.net/gpo-micro-api/ai/tool/query-dff-template'
      : 'https://cnapp-uat.sgs.net/gpo-micro-api/ai/tool/query-dff-template'
    
    const dffApiUrl = isProduction
      ? 'https://cnapp.sgs.net/DFFV2Api/dff/queryDff'
      : 'https://cnapp-uat.sgs.net/DFFV2Api/dff/queryDff'
    
    // console.log('查询DFF模板:', { objectType, objectNo, productLineCode, gpoApiUrl })
    
    // 第一步：调用GPO API获取模板ID
    const requestBody = {
      objectType,
      objectNo,
      productLineCode
    }
    // console.log('GPO API请求体:', JSON.stringify(requestBody, null, 2))
    
    const tryQuery = async (type) => {
      const body = { objectType: type, objectNo, productLineCode }
      const res = await fetch(gpoApiUrl, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(body)
      })
      if (!res.ok) {
        const errorText = await res.text()
        return { ok: false, status: res.status, statusText: res.statusText, errorText, body }
      }
      const json = await res.json()
      return { ok: true, json, body, status: res.status }
    }

    let primary = await tryQuery(objectType)
    let gpoResult = primary.ok ? primary.json : null
    let usedType = objectType
    let attempts = [primary]
    
    if (!primary.ok || !gpoResult?.success || !gpoResult?.data) {
      const altType = objectType === 'Order' ? 'Enquiry' : 'Order'
      const secondary = await tryQuery(altType)
      attempts.push(secondary)
      if (secondary.ok && secondary.json?.success && secondary.json?.data) {
        gpoResult = secondary.json
        usedType = altType
      } else {
        ctx.body = {
          success: false,
          message: `GPO API返回失败或无数据`,
          data: { attempts },
          debug: {
            requestUrl: gpoApiUrl,
            objectNo,
            productLineCode,
            objectTypeTried: [objectType, altType]
          }
        }
        return
      }
    }
    // console.log('GPO API响应:', JSON.stringify(gpoResult, null, 2))
    
    const { productTemplateId, productSamplesTemplateId } = gpoResult.data
    
    // 第二步：使用获取到的模板ID查询具体的DFF字段和值
    const dffResults = {}
    let rawProductDffData = null
    let rawSamplesDffData = null
    
    // 查询产品模板DFF
    if (productTemplateId) {
      try {
        const productFormData = new FormData()
        productFormData.append('id', productTemplateId)
        
        // console.log('开始查询产品模板DFF，ID:', productTemplateId)
        
        const productDffResponse = await fetch(dffApiUrl, {
          method: 'POST',
          body: productFormData,
          timeout: 10000,
          headers: {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
          }
        })
        
        if (productDffResponse.ok) {
          const productDffData = await productDffResponse.json()
          // console.log('产品模板DFF查询响应:', JSON.stringify(productDffData, null, 2))
          
          // 保存原始数据
          rawProductDffData = productDffData
          
          // 检查响应数据的有效性
          if (Array.isArray(productDffData) && productDffData.length === 0) {
            console.warn('产品模板DFF查询返回空数组，可能的原因:')
            console.warn('1. 模板ID无效或不存在')
            console.warn('2. 模板没有配置DFF字段')
            console.warn('3. 权限不足或认证问题')
            console.warn('4. API服务器内部错误')
          }
          
          // 处理DFF数据，提取字段信息（保留用于兼容性）
          const processedProductData = processDffData(productDffData)
          dffResults.productTemplate = processedProductData
          // console.log('产品模板DFF处理后数据:', JSON.stringify(processedProductData, null, 2))
        } else {
          const errorText = await productDffResponse.text()
          console.warn('产品模板DFF查询失败:', productDffResponse.status, productDffResponse.statusText)
          console.warn('错误详情:', errorText)
        }
      } catch (error) {
        console.error('产品模板DFF查询错误:', error)
      }
    }
    
    // 查询样品模板DFF
    if (productSamplesTemplateId) {
      try {
        const samplesFormData = new FormData()
        samplesFormData.append('id', productSamplesTemplateId)
        
        console.log('开始查询样品模板DFF，ID:', productSamplesTemplateId)
        
        const samplesDffResponse = await fetch(dffApiUrl, {
          method: 'POST',
          body: samplesFormData,
          timeout: 10000,
          headers: {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
          }
        })
        
        if (samplesDffResponse.ok) {
          const samplesDffData = await samplesDffResponse.json()
          // console.log('样品模板DFF查询响应:', JSON.stringify(samplesDffData, null, 2))
          
          // 保存原始数据
          rawSamplesDffData = samplesDffData
          
          // 检查响应数据的有效性
          if (Array.isArray(samplesDffData) && samplesDffData.length === 0) {
            console.warn('样品模板DFF查询返回空数组，可能的原因:')
            console.warn('1. 模板ID无效或不存在')
            console.warn('2. 模板没有配置DFF字段')
            console.warn('3. 权限不足或认证问题')
            console.warn('4. API服务器内部错误')
          }
          
          // 处理DFF数据，提取字段信息（保留用于兼容性）
          const processedSamplesData = processDffData(samplesDffData)
          dffResults.productSamplesTemplate = processedSamplesData
          // console.log('样品模板DFF处理后数据:', JSON.stringify(processedSamplesData, null, 2))
        } else {
          const errorText = await samplesDffResponse.text()
          console.warn('样品模板DFF查询失败:', samplesDffResponse.status, samplesDffResponse.statusText)
          console.warn('错误详情:', errorText)
        }
      } catch (error) {
        console.error('样品模板DFF查询错误:', error)
      }
    }
    
    // console.log('最终返回的DFF结果:', JSON.stringify(dffResults, null, 2))
    
    ctx.body = {
      success: true,
      message: 'DFF模板查询成功',
      data: {
        templateInfo: gpoResult.data,
        dffFields: dffResults,
        productDffResponse: rawProductDffData,
        samplesDffResponse: rawSamplesDffData,
        objectTypeUsed: usedType
      }
    }
    
  } catch (error) {
    console.error('DFF模板查询错误:', error)
    ctx.status = 200
    ctx.body = {
      success: false,
      message: 'DFF模板查询失败',
      error: error.message
    }
  }
}

// CSV生成schema
const csvGenerateSchema = z.object({
  orderNo: z.string().openapi({ description: 'Order number from headers' }),
  productDffData: z.array(z.any()).openapi({ description: 'Product DFF template data' })
}).openapi({ description: 'CSV generation request' })

const csvGenerateResponseSchema = z.object({
  success: z.boolean().openapi({ description: 'Generation success status', example: true }),
  message: z.string().openapi({ description: 'Response message', example: 'CSV generated successfully' }),
  data: z.object({
    csvContent: z.string().openapi({ description: 'CSV file content' }),
    fileName: z.string().openapi({ description: 'Generated CSV file name' })
  }).optional().openapi({ description: 'CSV file information' }),
  error: z.string().optional().openapi({ description: 'Error message if any' })
}).openapi({ description: 'CSV generation response' })

// 注册CSV生成API路径
registryFile.registerPath({
  method: 'post',
  path: '/api/file/generate-csv',
  summary: '生成DFF数据CSV文件',
  description: '根据产品模板DFF查询响应数据生成CSV文件',
  request: {
    body: {
      content: {
        'application/json': {
          schema: csvGenerateSchema
        }
      }
    }
  },
  responses: {
    200: {
      description: 'CSV文件生成成功',
      content: {
        'application/json': {
          schema: csvGenerateResponseSchema
        }
      }
    },
    400: {
      description: 'CSV生成失败',
      content: {
        'application/json': {
          schema: csvGenerateResponseSchema
        }
      }
    }
  }
})

// 生成CSV文件的控制器
export const generateCsvController = async (ctx) => {
  try {
    const { orderNo, productDffData } = ctx.request.body

    if (!orderNo || !productDffData || !Array.isArray(productDffData)) {
      ctx.status = 400
      ctx.body = {
        success: false,
        message: '缺少必要参数：orderNo 和 productDffData'
      }
      return
    }

    // 生成CSV内容（添加BOM以避免Excel显示中文乱码）
    const BOM = '\uFEFF'
    let csvContent = BOM + 'order_no,type,FieldCode,DisplayName\n'
    
    // 转义CSV中的特殊字符
    const escapeCsvValue = (value) => {
      if (value === null || value === undefined) return ''
      if (typeof value !== 'string') return String(value)
      if (value.includes(',') || value.includes('"') || value.includes('\n')) {
        return `"${value.replace(/"/g, '""')}"`
      }
      return value
    }
    
    // 添加Customer类型的固定行
    const customerFields = [
      'ApplicantName(In Chinese)',
      'PayerName(In Chinese)',
      'ApplicantContactPersonName',
      'PayerContactPersonName',
      'ApplicantContactPersonEmail',
      'PayerContactPersonEmail',
      'ApplicantName(In English)',
      'PayerName(In English)',
      'ManufacturerName(In English)'
    ]
    
    customerFields.forEach(field => {
      csvContent += `${escapeCsvValue(orderNo)},Customer,${escapeCsvValue(field)},${escapeCsvValue(field)}\n`
    })
    
    // 添加Service类型的固定行
    const serviceFields = [
      'SoftCopy Deliver To',
      'Report Language',
      'Service Type',
      'Invoice Deliver Way'
    ]
    
    serviceFields.forEach(field => {
      csvContent += `${escapeCsvValue(orderNo)},Service,${escapeCsvValue(field)},${escapeCsvValue(field)}\n`
    })
    
    // 添加报告抬头相关的固定DisplayName，FieldCode为空
    const fixedReportHeaderFields = [
      'Name and Address of the Customer报告抬头',
      'Name of the Customer报告抬头',
      'Address of the Customer报告抬头',
      'report header is different from applicant Company Name',
      'report header is different from applicant Address'
    ]
    fixedReportHeaderFields.forEach(name => {
      csvContent += `${escapeCsvValue(orderNo)},Service,,${escapeCsvValue(name)}\n`
    })
    
    // 添加DFF数据行
    productDffData.forEach(item => {
      // 确保fieldCode和dispalyName一一对应，即使其中一个为空也要生成行
      const fieldCode = item.fieldCode || ''
      const displayName = item.dispalyName || ''
      
      // 每个DFF项都生成一行，即使fieldCode或displayName为空
      csvContent += `${escapeCsvValue(orderNo)},DFF,${escapeCsvValue(fieldCode)},${escapeCsvValue(displayName)}\n`
    })

    const fileName = `dff_data_${orderNo}_${Date.now()}.csv`

    ctx.status = 200
    ctx.body = {
      success: true,
      message: 'CSV文件生成成功',
      data: {
        csvContent,
        fileName
      }
    }

  } catch (error) {
    console.error('CSV生成错误:', error)
    try {
      const ord = ctx.request.body?.orderNo || ''
      await sendErrorMail(ctx, ord, 'CSV已生成', error?.message || String(error))
    } catch {}
    ctx.status = 500
    ctx.body = {
      success: false,
      message: 'CSV文件生成失败',
      error: error.message
    }
  }
}

export const clearAllFilesController = async (ctx) => {
  try {
    const uploadsDir = path.join(process.cwd(), 'uploads')
    
    // 检查uploads目录是否存在
    if (!fs.existsSync(uploadsDir)) {
      ctx.body = {
        success: true,
        message: '上传目录不存在，无需清理',
        data: {
          deletedFiles: 0,
          totalSize: 0
        }
      }
      return
    }
    
    // 读取目录中的所有文件
    const files = fs.readdirSync(uploadsDir)
    let deletedFiles = 0
    let totalSize = 0
    
    // 删除所有文件
    for (const file of files) {
      const filePath = path.join(uploadsDir, file)
      const stats = fs.statSync(filePath)
      
      if (stats.isFile()) {
        totalSize += stats.size
        fs.unlinkSync(filePath)
        deletedFiles++
      }
    }
    
    ctx.body = {
      success: true,
      message: `成功清理 ${deletedFiles} 个文件，释放空间 ${(totalSize / 1024 / 1024).toFixed(2)} MB`,
      data: {
        deletedFiles,
        totalSize
      }
    }
  } catch (error) {
    console.error('清理文件错误:', error)
    ctx.status = 500
    ctx.body = {
      success: false,
      message: '清理文件失败',
      error: error.message
    }
  }
}

// TRF缓存统计控制器
export const getTrfCacheStatsController = async (ctx) => {
  try {
    const stats = await getTrfCacheStats()
    
    ctx.body = {
      success: true,
      message: '获取TRF缓存统计信息成功',
      data: stats
    }
  } catch (error) {
    console.error('获取TRF缓存统计信息错误:', error)
    ctx.status = 500
    ctx.body = {
      success: false,
      message: '获取TRF缓存统计信息失败',
      error: error.message
    }
  }
}

// TRF缓存清理控制器
export const cleanTrfCacheController = async (ctx) => {
  try {
    const { maxAge, maxFiles, specificFiles } = ctx.request.body
    
    const options = {}
    
    // 处理时间参数（支持天数转换为毫秒）
    if (maxAge) {
      if (typeof maxAge === 'number') {
        options.maxAge = maxAge
      } else if (typeof maxAge === 'string' && maxAge.endsWith('d')) {
        const days = parseInt(maxAge.replace('d', ''))
        options.maxAge = days * 24 * 60 * 60 * 1000 // 转换为毫秒
      }
    }
    
    if (maxFiles) {
      options.maxFiles = parseInt(maxFiles)
    }
    
    if (specificFiles && Array.isArray(specificFiles)) {
      options.specificFiles = specificFiles
    }
    
    const result = await cleanTrfCache(options)
    
    ctx.body = {
      success: true,
      message: result.message,
      data: result
    }
  } catch (error) {
    console.error('清理TRF缓存错误:', error)
    ctx.status = 500
    ctx.body = {
      success: false,
      message: '清理TRF缓存失败',
      error: error.message
    }
  }
}

// 清理所有TRF缓存控制器
export const clearAllTrfCacheController = async (ctx) => {
  try {
    const result = await clearAllTrfCache()
    
    ctx.body = {
      success: true,
      message: result.message,
      data: result
    }
  } catch (error) {
    console.error('清理所有TRF缓存错误:', error)
    ctx.status = 500
    ctx.body = {
      success: false,
      message: '清理所有TRF缓存失败',
      error: error.message
    }
  }
}

// 获取所有缓存统计信息控制器
export const getAllCacheStatsController = async (ctx) => {
  try {
    const stats = await getAllCacheStats()
    
    ctx.body = {
      success: true,
      message: '获取缓存统计信息成功',
      data: stats
    }
  } catch (error) {
    console.error('获取缓存统计信息错误:', error)
    ctx.status = 500
    ctx.body = {
      success: false,
      message: '获取缓存统计信息失败',
      error: error.message
    }
  }
}

// 清理指定类型缓存控制器
export const cleanCacheByTypeController = async (ctx) => {
  try {
    const { cacheType, maxAge, maxFiles, specificFiles } = ctx.request.body
    
    if (!cacheType) {
      ctx.status = 400
      ctx.body = {
        success: false,
        message: '缺少必要参数：cacheType'
      }
      return
    }

    // 根据当前策略，禁用临时文件缓存清理
    if (cacheType === 'temp') {
      ctx.status = 400
      ctx.body = {
        success: false,
        message: '临时文件缓存（temp）不支持清理操作'
      }
      return
    }
    
    const options = {}
    
    // 处理时间参数
    if (maxAge) {
      if (typeof maxAge === 'number') {
        options.maxAge = maxAge
      } else if (typeof maxAge === 'string' && maxAge.endsWith('d')) {
        const days = parseInt(maxAge.replace('d', ''))
        options.maxAge = days * 24 * 60 * 60 * 1000
      } else if (typeof maxAge === 'string' && maxAge.endsWith('h')) {
        const hours = parseInt(maxAge.replace('h', ''))
        options.maxAge = hours * 60 * 60 * 1000
      }
    }
    
    if (maxFiles) {
      options.maxFiles = parseInt(maxFiles)
    }
    
    if (specificFiles && Array.isArray(specificFiles)) {
      options.specificFiles = specificFiles
    }
    
    const result = await cleanCacheByType(cacheType, options)
    
    ctx.body = {
      success: true,
      message: result.message,
      data: result
    }
  } catch (error) {
    console.error('清理缓存错误:', error)
    ctx.status = 500
    ctx.body = {
      success: false,
      message: '清理缓存失败',
      error: error.message
    }
  }
}

// 清理所有类型缓存控制器
export const clearAllCacheController = async (ctx) => {
  try {
    // 从请求体或查询参数中获取缓存类型，如果都没有则使用默认值
    const requestedTypes = ctx.request.body?.cacheTypes || ctx.query.cacheTypes || ['trf', 'uploads', 'processed', 'logs']
    // 过滤掉临时文件缓存类型
    const cacheTypes = Array.isArray(requestedTypes) ? requestedTypes.filter(t => t !== 'temp') : ['trf', 'uploads', 'processed', 'logs']
    
    console.log('清理缓存类型:', cacheTypes)
    
    const result = await clearAllCache(cacheTypes)
    
    ctx.body = {
      success: true,
      message: result.message,
      data: result
    }
  } catch (error) {
    console.error('清理所有缓存错误:', error)
    ctx.status = 500
    ctx.body = {
      success: false,
      message: '清理所有缓存失败',
      error: error.message
    }
  }
}

// 获取缓存详情控制器
export const getCacheDetailsController = async (ctx) => {
  try {
    const { cacheType } = ctx.params
    
    if (!cacheType) {
      ctx.status = 400
      ctx.body = {
        success: false,
        message: '缓存类型参数不能为空'
      }
      return
    }

    const cacheDetails = await getCacheStatsByType(cacheType)
    
    ctx.body = {
      success: true,
      message: '获取缓存详情成功',
      data: cacheDetails
    }
  } catch (error) {
    console.error('获取缓存详情时出错:', error)
    ctx.status = 500
    ctx.body = {
      success: false,
      message: '获取缓存详情失败',
      error: error.message
    }
  }
}

// 订单/询价状态检查控制器
export const queryOrderStatusController = async (ctx) => {
  try {
    const { objectNo, objectType = 'order' } = ctx.request.body
    if (!objectNo) {
      ctx.status = 400
      ctx.body = { success: false, message: '缺少必需参数: objectNo' }
      return
    }
    const type = (objectType || 'order').toLowerCase()
    const sgsToken = ctx.state.user?.sgsToken || ctx.headers.sgstoken || ctx.headers.Sgstoken || ''
    let id = null
    let detail = null
    let sampleData = null
    const errors = []
    if (type === 'order') {
      id = await getOrderId(objectNo, sgsToken)
      if (id) {
        detail = await getOrderDetail(id, sgsToken)
        sampleData = await getSampleDataByOrderId(id, sgsToken)
      } else {
        errors.push('ORDER_NOT_FOUND')
      }
    } else if (type === 'enquiry') {
      if (!sgsToken) {
        errors.push('MISSING_TOKEN')
      } else {
        id = await getEnquiryId(objectNo)
        if (id) {
          detail = await getEnquiryDetail(id, sgsToken)
          sampleData = await getSampleDataByEnquiryId(id, sgsToken)
        } else {
          errors.push('ENQUIRY_NOT_FOUND')
        }
      }
    } else {
      ctx.status = 400
      ctx.body = { success: false, message: 'objectType必须是order或enquiry' }
      return
    }
    const orderStatus = detail?.statusName || detail?.status || null
    const reportStatusList = Array.isArray(detail?.reportList) ? detail.reportList.map(r => r?.statusName || r?.status || null) : []
    const hasDff = !!(sampleData?.productSampleRspList && sampleData.productSampleRspList.length > 0)
    const productSamplesCount = hasDff ? (sampleData.productSampleRspList[0]?.productSamples?.length || 0) : 0

    // 判断是否存在有效的 ServiceRequirement（根据文档，如果为空则不支持更新）
    const sr = detail?.serviceRequirement || null
    const hasServiceRequirement = !!(sr && (
      (Array.isArray(sr.contactInfos) && sr.contactInfos.length > 0) ||
      sr.invoiceDeliverWay ||
      sr.returnResidueSampleFlag !== undefined ||
      sr.returnResidueSampleRemark ||
      sr.returnTestedSampleFlag !== undefined
    ))

    const blockedReasons = []
    if (!id) blockedReasons.push('记录不存在')
    if (!hasDff) blockedReasons.push('缺少DFF/样品信息')
    if (!hasServiceRequirement) blockedReasons.push('ServiceRequirement为空')

    // 订单状态不允许更新
    const disallowStatuses = ['Cancelled', 'Closed', 'Pending', 'Completed']
    if (orderStatus && disallowStatuses.includes(orderStatus)) {
      blockedReasons.push(`订单状态不允许更新: ${orderStatus}`)
    }

    // Report存在非New状态不允许更新（根据文档）
    const nonNewReports = reportStatusList.filter(s => s && s !== 'New')
    if (nonNewReports.length > 0) {
      blockedReasons.push(`存在非New的Report状态: ${nonNewReports.join(',')}`)
    }

    const canUpdate = blockedReasons.length === 0
    ctx.body = {
      success: true,
      message: '订单/询价状态检查完成',
      data: {
        type,
        id,
        orderStatus,
        reportStatusList,
        hasDff,
        hasServiceRequirement,
        productSamplesCount,
        canUpdate,
        blockedReasons,
        detail,
        sampleData
      }
    }
  } catch (error) {
    console.error('订单状态检查错误:', error)
    ctx.status = 500
    ctx.body = { success: false, message: '订单状态检查失败', error: error.message }
  }
}

// TRF to GPO控制器
export const trfToGpoController = async (ctx) => {
  try {
    const { orderNo, trfResult, objectType = 'order' } = ctx.request.body
    
    if (!orderNo) {
      ctx.status = 400
      ctx.body = {
        success: false,
        message: '订单号不能为空'
      }
      return
    }
    
    if (!trfResult) {
      ctx.status = 400
      ctx.body = {
        success: false,
        message: 'TRF结果数据不能为空'
      }
      return
    }
    
    console.log(`开始TRF to GPO处理: ${orderNo}`)
    
    // 解析TRF结果数据
    const extractedData = parseTrfResult(trfResult)
    
    if (!extractedData || Object.keys(extractedData).length === 0) {
      ctx.status = 400
      ctx.body = {
        success: false,
        message: 'TRF结果中没有找到有效的字段数据'
      }
      return
    }
    
    // 获取用户的SGS Token
    const sgsToken = ctx.state.user?.sgsToken
    if (!sgsToken) {
      ctx.status = 401
      ctx.body = {
        success: false,
        message: '缺少SGS Token，请重新登录'
      }
      return
    }
    
    // 调用GPO API更新字段
    const { requestData: gpoRequestData, result: updateResult } = await updateGpoFields(orderNo, extractedData, objectType, sgsToken)
    try {
      const ok = updateResult?.success
      if (!ok) {
        const msg = updateResult?.message || 'GPO更新失败'
        await sendErrorMail(
          ctx,
          orderNo,
          'GPO更新失败',
          JSON.stringify({ message: msg, result: updateResult })
        )
      }
    } catch {}

    ctx.body = {
      success: true,
      message: `TRF数据已成功推送到GPO (${orderNo})`,
      data: {
        orderNo,
        objectType,
        updatedFields: Object.keys(extractedData).length,
        extractedData,
        updateResult,
        gpoRequestData
      }
    }
    
  } catch (error) {
    console.error('TRF to GPO处理错误:', error)
    try {
      const ord = ctx.request.body?.orderNo || ''
      await sendErrorMail(ctx, ord, '推送GPO中', error?.message || String(error))
    } catch {}
    ctx.status = 500
    ctx.body = {
      success: false,
      message: `TRF to GPO处理失败: ${error.message}`,
      error: error.message
    }
  }
}

// 检查文件是否已处理过（供上传前重复检测使用）
export const checkFileExistsController = async (ctx) => {
  try {
    const { fileName, fileNames } = ctx.request.body || {}
    const names = Array.isArray(fileNames) && fileNames.length > 0
      ? fileNames
      : (typeof fileName === 'string' && fileName.trim() ? [fileName] : [])

    if (names.length === 0) {
      ctx.status = 400
      ctx.body = { success: false, message: '缺少必需参数: fileName或fileNames' }
      return
    }

    const duplicates = {}
    let totalMatches = 0
    for (const name of names) {
      const base = name.replace(/\.[^/.]+$/, '')
      const records = findProcessedRecordsByKey(base)
      const totalCount = records.reduce((sum, r) => sum + (typeof r.processCount === 'number' ? r.processCount : 1), 0)
      duplicates[name] = {
        exists: records.length > 0,
        count: totalCount,
        recordCount: records.length,
        records
      }
      totalMatches += totalCount
    }

    const anyExists = Object.values(duplicates).some(r => r.exists)
    ctx.body = {
      success: true,
      message: '重复文件检查完成',
      data: { duplicates, anyExists, totalMatches }
    }
  } catch (error) {
    console.error('检查文件是否已处理错误:', error)
    ctx.status = 500
    ctx.body = { success: false, message: '检查失败', error: error.message }
  }
}

export const clearAllProcessedRecordsController = async (ctx) => {
  try {
    writeProcessedRegistry([])
    ctx.body = { success: true, message: '处理记录已全部清空', data: { remainingCount: 0 } }
  } catch (error) {
    console.error('清空处理记录错误:', error)
    ctx.status = 500
    ctx.body = { success: false, message: '清空处理记录失败', error: error.message }
  }
}

async function sendErrorMail(ctx, orderNo, phase, errorInfo) {
  try {
    const sgsToken = ctx.state?.user?.sgsToken || ''
    let labCode = ctx.state?.user?.labCode || ''
    let buCode = ctx.state?.user?.locationCode || ''
    let mailSender = ctx.state?.user?.email || ''
    let sendBy = ctx.state?.user?.uname || ''
    let labInfoRaw = null
    try {
      if (sgsToken) {
        const info = await getUserLabBuInfo(sgsToken)
        labInfoRaw = info || null
        labCode = info?.labCode || labCode
        buCode = info?.buCode || info?.locationCode || buCode
      }
    } catch {}
    const isProduction = process.env.NODE_ENV === 'production'
    const url = isProduction
      ? 'http://cnapp.sgs.net/NotificationApi/notification/sendMail'
      : 'http://cnapp-uat.sgs.net/NotificationApi/notification/sendMail'
    try {
      if (sgsToken) {
        const base = isProduction ? 'http://cnapp.sgs.net' : 'http://cnapp-uat.sgs.net'
        const userUrl = `${base}/UserManagementApi/dimension/getUserBasicInfoByToken/${sgsToken}`
        const resp = await fetch(userUrl, { method: 'GET' })
        const json = await resp.json()
        if (json?.success && json?.data) {
          mailSender = json.data.email || mailSender
          sendBy = json.data.name || sendBy
          labCode = json.data?.laboratory?.labCode || labCode
          buCode = json.data?.location?.locationCode || buCode
        }
      }
    } catch {}
    const timestamp = new Date().toISOString()
    const mailText = [
      `阶段: ${phase}`,
      `单号: ${orderNo}`,
      `错误: ${errorInfo}`,
      `用户名: ${sendBy}`,
      `用户邮箱: ${mailSender}`,
      `实验室: ${ctx.state?.user?.labCode || ''}`
    ].join('<br/>')
    const payload = {
      systemId: '15',
      labCode: labCode || '',
      buCode: buCode || '',
      mailSender: mailSender || '',
      sendBy: sendBy || '',
      templateType: '',
      objectNo: String(orderNo || ''),
      mailFrom: 'TRF to GPO',
      mailSubject: 'TRF to GPO error ',
      mailText,
      mailTo: ['glenn.gao@sgs.com'],
      mailCc: ['']
    }
    console.log('发送错误邮件请求体:', JSON.stringify(payload))
    await fetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(payload)
    })
  } catch (e) {
    console.warn('发送错误邮件失败:', e?.message || e)
  }
}